﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OverSATbLib
{
    /// <summary>
    /// Tuple set is a collection of tuples that can be normalized, among other things.
    /// </summary>
    public class TupleSet
    {
        public List<Tuple> Tuples { get; private set; }
        public SatSolver Solver { get; set; }

        public TupleSet()
        {
            Tuples = new List<Tuple>();
        }

        /// <summary>
        /// Rewrite the list of tuples so that it has no duplicates and does not overlap.
        /// </summary>
        public void Normalize()
        { 
            int passcount = 0;
            bool normalizing = true;

            while (normalizing)
            {
                string output = string.Format( "{0} ) {1} tuples", passcount++, Tuples.Count );
                Console.WriteLine(output);
                System.Diagnostics.Debug.WriteLine(output);
                normalizing = NormalizePass();
            }
        }

        /// <summary>
        /// Transforms the supplied list of tuples
        /// </summary>
        /// <param name="tuples"></param>
        /// <param name="transformer"></param>
        /// <returns></returns>
        private bool Transform( List<Tuple> tuples, Func<Tuple, Tuple, List<Tuple>, List<Tuple>> transformer)
        {
            Dictionary<Tuple, Tuple> uniqueTuples = new Dictionary<Tuple, Tuple>(  Tuple.TupleEquality );
            List<Tuple> cancelledTuples = new List<Tuple>();

            for (int i = 0; i < tuples.Count; i++)
            {
                var ti = tuples[i];

                for (int j = i + 1; j < tuples.Count; j++)
                {
                    var tj = tuples[j];

                    var results = transformer(ti, tj, cancelledTuples);

                    if (results != null)
                    {
                        for (int k = 0; k < results.Count; k++)
                        {
                            var tk = results[k];
                            Solver.RegisterTuple(tk);
                            var tks = tk.ToString();
                            if (!uniqueTuples.ContainsKey( tk ))
                            {
                                uniqueTuples.Add(tk, tk);
                            }
                        }
                    }
                }
            }

            foreach (var ct in cancelledTuples)
            {
                if (uniqueTuples.ContainsKey(ct))
                {
                    uniqueTuples.Remove(ct);
                }
            }

            var utvl = uniqueTuples.Values.ToList();

            var modifiedTuples = utvl.Join(tuples,
                a => a.ToString(),
                b => b.ToString(),
                (a, b) =>
                new
                {
                    a,
                    b
                }).ToList();

            if (modifiedTuples.Count != tuples.Count)
            {
                tuples.Clear();
                tuples.AddRange(utvl);
                return true;
            }
            else
            {
                return false;
            }
        }

        private bool NormalizePass()
        {
            bool transformedA = false;
            bool transformedB = false;

            transformedA = Transform(Tuples, (a, b, l) =>
                {
                    return a.ExactOr(b, l);
                }
            );

            transformedB = Transform(Tuples, (a, b, l) =>
                {
                    return a.CancelTuple(b, l);
                }
            );

            return transformedA || transformedB;
        }

    }
}
